package wshandler

import (
	"encoding/json"
	"fmt"

	"starsine.cn/appTpl/cmn/logs"
	"starsine.cn/appTpl/svccenter/registry/grpc/scregistryproto"
	"starsine.cn/appTpl/svclog/cmd"
	"starsine.cn/appTpl/svclog/src/fe/chan2client"
	"starsine.cn/appTpl/svclog/src/fe/openapi"
	"starsine.cn/appTpl/svclog/src/fe/ws-server/wsserver"
	festrung "starsine.cn/appTpl/svclog/src/logproc/fe-strung"
	"starsine.cn/appTpl/svclog/src/svclogpubsub"
	"starsine.cn/appTpl/svcpeers"
	"starsine.cn/appTpl/svcpeers/svcpeersproto"
	"starsine.cn/appTpl/svcregistry"
	"starsine.cn/appTpl/svcregistry/grpc/client"
)

func WsMsgHandler(conn *wsserver.WsServer, msg []byte) {
	head := openapi.WsRequestTpl{}
	err := json.Unmarshal(msg, &head)
	if err != nil {
		logs.Warnf("WsMsgHandler Unmarshal fail, err: %s", err)
		return
	}

	if head.MsgHead.ResOrReq != "req" {
		return
	}

	c, ok := chan2client.GetUserFromWsConn(conn)
	if !ok {
		logs.Warnf("WsMsgHandler %s from wsServer, but svc is not exist, drop it.", head.MsgHead.RequestType)
		return
	}
	logs.Debugf("WsMsgHandler process %s msg from client: %s", head.MsgHead.RequestType, c)

	switch head.MsgHead.RequestType {
	case "ws-heartbeat", "fe-heartbeat":
	case "svc-get-all":
		// v := map[string]openapi.SvcInfo{}
		all, err := client.SvcGetAll(&scregistryproto.SvcGetAllReq{})
		if err != nil {
			logs.Warnf("WsMsgHandler(%s) SvcGetAll fail, err: %s", head.MsgHead.RequestType, err)
			return
		}

		v := map[string]interface{}{}
		for id, svc := range all.Svcs {
			v[id] = svc
		}
		conn.SendMessage(&openapi.WsSvcGetAllRes{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "res",
				RequestType: head.MsgHead.RequestType,
				SerialNum:   head.MsgHead.SerialNum,
				Message:     fmt.Sprintf("svc get all ok"),
				Status:      "ok",
			},
			Data: v,
		})

	case "svc-update-sub":
		svclogpubsub.FeSubSvcUpdate(conn)

		conn.SendMessage(&openapi.WsSvcUpdateSubRes{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "res",
				RequestType: head.MsgHead.RequestType,
				SerialNum:   head.MsgHead.SerialNum,
				Message:     fmt.Sprintf("svc update sub ok"),
				Status:      "ok",
			},
		})

	case "svc-update-unsub":
		svclogpubsub.FeUnSubSvcUpdate(conn)

		conn.SendMessage(&openapi.WsSvcUpdateUnSubRes{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "res",
				RequestType: head.MsgHead.RequestType,
				SerialNum:   head.MsgHead.SerialNum,
				Message:     fmt.Sprintf("svc update unsub ok"),
				Status:      "ok",
			},
		})

	case "command-execute":
		command := openapi.WsCmdLineReq{}
		err := json.Unmarshal(msg, &command)
		if err != nil {
			logs.Warnf("WsMsgHandler Unmarshal WsCmdLineReq fail, err: %s", err)
			return
		}

		out := ""
		if svcregistry.GetInstanceID() == command.Data.InstanceID {
			out = cmd.CmdExec(command.Data.CmdLine)
		} else {
			all, err := client.SvcGetAll(&scregistryproto.SvcGetAllReq{})
			if err != nil {
				logs.Warnf("WsMsgHandler(%s) SvcGetAll fail, err: %s", head.MsgHead.RequestType, err)
				return
			}
			svc, ok := all.Svcs[command.Data.InstanceID]
			if !ok {
				logs.Warnf("WsMsgHandler(%s) SvcGet(%s) fail, err: %s", head.MsgHead.RequestType, command.Data.InstanceID, err)
				return
			}

			c := svcpeers.GetSvcClient(command.Data.InstanceID, svc.RpcAddr)
			if c == nil {
				logs.Warn("svcpeers.GetSvcClient fail")
				return
			}

			v, err := c.CmdLine(&svcpeersproto.CmdLIneReq{
				CmdLine: command.Data.CmdLine,
			})
			if err != nil {
				logs.Warnf("WsMsgHandler(%s) svc(%s, addr:%s) CmdLine(%s) fail, err: %s", head.MsgHead.RequestType, command.Data.InstanceID, svc.RpcAddr, command.Data.CmdLine, err)
				return
			}
			out = v.Out
		}

		conn.SendMessage(&openapi.WsCmdLineRes{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "res",
				RequestType: head.MsgHead.RequestType,
				SerialNum:   head.MsgHead.SerialNum,
				Message:     fmt.Sprintf("command execute ok"),
				Status:      "ok",
			},
			Data: openapi.CmdLineResData{
				CmdLine: command.Data.CmdLine,
				Out:     out,
			},
		})

	case "start-imme-log":
		v := openapi.WsImmeLogReq{}
		err := json.Unmarshal(msg, &v)
		if err != nil {
			logs.Warnf("WsMsgHandler Unmarshal WsImmeLogReq fail, err: %s", err)
			return
		}

		festrung.Create(v.Data.InstanceID, conn)

		conn.SendMessage(&openapi.WsImmeLogRes{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "res",
				RequestType: head.MsgHead.RequestType,
				SerialNum:   head.MsgHead.SerialNum,
				Message:     fmt.Sprintf("create imme-log of instance(%s) ok", v.Data.InstanceID),
				Status:      "ok",
			},
		})

	case "end-imme-log":
		v := openapi.WsImmeLogReq{}
		err := json.Unmarshal(msg, &v)
		if err != nil {
			logs.Warnf("WsMsgHandler Unmarshal WsImmeLogReq fail, err: %s", err)
			return
		}

		festrung.CloseConn(v.Data.InstanceID, conn)

		conn.SendMessage(&openapi.WsImmeLogRes{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "res",
				RequestType: head.MsgHead.RequestType,
				SerialNum:   head.MsgHead.SerialNum,
				Message:     fmt.Sprintf("CloseConn imme-log of instance(%s) ok", v.Data.InstanceID),
				Status:      "ok",
			},
		})

	default:
		logs.Warnf("WsMsgHandler get unknown request type: %s", head.MsgHead.RequestType)
	}
}
